#pragma once

#include <stdio.h>
#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <stdarg.h>
#include <pthread.h>
#include <unistd.h>
#include <mutex>
#include <thread>
#include <functional>
#include <condition_variable>

using namespace std;

// 打印宏
#define _DEBUG(...) LoggerMng::ptrInstance().get()->writeLog(LoggerMng::LEVEL_DEBUG, __VA_ARGS__)
#define _INFO(...)  LoggerMng::ptrInstance().get()->writeLog(LoggerMng::LEVEL_INFO, __VA_ARGS__)
#define _WARN(...)  LoggerMng::ptrInstance().get()->writeLog(LoggerMng::LEVEL_WARN, __VA_ARGS__)
#define _ERROR(...) LoggerMng::ptrInstance().get()->writeLog(LoggerMng::LEVEL_ERROR, __VA_ARGS__)

#define LOG_FILE_PATH       "./log"
#define INIT_GARBAGE          1

/**
 * @brief The LoggerMng class               日志管理类
 */
class LoggerMng
{
public:
    ~LoggerMng();

    // 日志等级
    enum LOG_LEVEL
    {
        LEVEL_DEBUG = 0,
        LEVEL_INFO,
        LEVEL_WARN,
        LEVEL_ERROR
    };

    // 改进1: 利用其他类的析构来回收单例对象
    static LoggerMng *getInstance();
    class GarbageCollector
    {
    public:
        ~GarbageCollector()
        {
            std::cout << __PRETTY_FUNCTION__ << std::endl;
            if ( m_pInstance )
            {
                delete m_pInstance;
                m_pInstance = nullptr;
            }
        }
    };
    static GarbageCollector gc;


    /**
     * @brief Instance
     * @return
     */
    //改进2: 使用静态局部变量(注意：要使用引用，不然外面调用会引起新的一次构建)
    static LoggerMng &Instance();

    // 改进3: 使用智能指针自动释放
    static unique_ptr<LoggerMng> &ptrInstance();

    /**
     * @brief init                          初始化日志类
     * @return
     */
    bool init(const string &filePath);

    /**
     * @brief writeLog                      写文件
     */
    void writeLog(const LOG_LEVEL &level, const char* format, ...);

private:
    LoggerMng();
    LoggerMng(LoggerMng &l) = delete;
    LoggerMng &operator=(LoggerMng &l) = delete;

    inline string level2Str(const LOG_LEVEL &level);

    static LoggerMng *m_pInstance;
    static unique_ptr<LoggerMng> m_ptrInstance;

    /**
     * @brief threadWriteLog                写日志线程
     */
    void threadWriteLog();

    bool m_isExit = false;                      //  线程是否结束
    int m_today = 1993;                         // 日期比较
    FILE *m_pFile = nullptr;                    // 文件句柄
    std::mutex m_mutex;                         // 互斥锁
    unique_ptr<std::thread> m_threadPtr;        // 线程指针
    std::condition_variable m_conVar;           // 条件变量
    std::list<std::string> m_strList;           // 字符队列, 存放打印字符
};

